﻿namespace Furesoft.Styling
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Windows.Forms;

    using Furesoft.Styling.Converters;
    using Furesoft.Styling.Parser;
    using Furesoft.Styling.Transitions;
    using Furesoft.Styling.Winforms;

    internal class StyleChanger
    {
        #region Static Fields

        public static Control.ControlCollection controls;

        public static StylableForm form;

        #endregion

        #region Public Methods and Operators

        public static void Execute(string b)
        {
           // b = Importer.Import(b);

            IEnumerable<CssParserRule> p = new CssParser().ParseAll(b);
            foreach (CssParserRule cssParserRule in p)
            {
                foreach (string sel in cssParserRule.Selectors)
                {
                    var selector = sel.Replace("#", "").Replace(".", "");
                    if (!IsForm(selector))
                    {
                        foreach (Control bb in GetControls(controls, selector))
                        {
                            if (bb is Control)
                            {
                                Control bbb = bb;
                                if (bbb != null)
                                {
                                    ExecuteQuery(bbb, cssParserRule);
                                }
                            }
                        }
                    }
                    if (IsEvent(selector))
                    {
                        foreach (Control bb in GetControls(controls, GetEvent(selector).Key))
                        {
                            if (bb is Control)
                            {
                                Control bbb = bb;
                                if (bbb != null)
                                {
                                    if (bbb.Name == GetEvent(selector).Key)
                                    {
                                        ExecuteQuery(bbb, cssParserRule);
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        ExecuteQuery(form, cssParserRule);
                    }
                }
            }
        }

        public static void Init(Control.ControlCollection cc, StylableForm f)
        {
            controls = cc;
            form = f;
        }

        public static bool IsEvent(string selector)
        {
            return selector.Trim().Contains(":");
        }

        public static bool IsForm(string s)
        {
            if (!Contains(s))
            {
                return "#" + form.Name == s || "." + form.Class == s;
            }
            return false;
        }

        public static void Reset()
        {
            form.Controls.Clear();
            foreach (Control control in controls)
            {
                form.Controls.Add(control);
            }
        }

        #endregion

        #region Methods

        private static string BuildSection(CssParserRule rule)
        {
            return BuildSection(rule.Selectors.First(), rule);
        }

        private static string BuildSection(string section, CssParserRule rule)
        {
            var sb = new StringBuilder();

            sb.AppendLine(section + "{");

            foreach (CssParserDeclaration dec in rule.Declarations)
            {
                sb.AppendLine(dec.Property + ": " + dec.Value + ";");
            }

            sb.AppendLine("}");

            return sb.ToString();
        }

        private static bool Contains(string d)
        {
            return controls.ContainsKey(d);
        }

        private static void ExecuteQuery(Control bbb, CssParserRule cssParserRule)
        {
            foreach (CssParserDeclaration d in cssParserRule.Declarations)
            {
                if (d.Property.Contains("."))
                {
                    if (form.Controls.ContainsKey(d.Property.Split('.')[0]))
                    {
                        bbb = form.Controls[d.Property.Split('.')[0]];
                    }
                    else if (form.Name == d.Property.Split('.')[0])
                    {
                        bbb = form;
                    }
                }

                foreach (string selector in cssParserRule.Selectors)
                {
                    if (!IsEvent(selector))
                    {
                        if (selector == bbb.GetType().BaseType.Name || "#" + bbb.Name == selector || "." + bbb.Name == selector)
                        {
                            PropertyInfo prop = bbb.GetType().GetProperty(d.Property);

                            if (prop != null)
                            {
                                bool succees = true;

                                prop.SetValue(bbb, Converter.Convert(d.Value, prop.PropertyType, ref succees), null);

                                if (prop.PropertyType.Name == typeof(Transition).Name)
                                {
                                    Transition t = new TransitionConverter().Convert(d.Value, bbb);
                                    prop.SetValue(bbb, t, null);
                                    t.run();
                                }
                            }
                        }
                    }
                    else
                    {
                        EventInfo ei = bbb.GetType().GetEvent(GetEvent(selector).Value);
                        string se = BuildSection(GetEvent(selector).Key, cssParserRule);
                        try
                        {
                            ei.AddEventHandler(bbb, new EventHandler((sender, e) => Execute(se)));
                        }
                        catch (Exception e)
                        {
                            MessageBox.Show(e.Message);
                        }
                    }
                }
            }
        }

        private static Control[] GetControls(Control.ControlCollection cc, string selector)
        {
            var ret = new List<Control>();

            foreach (Control c in cc)
            {
                if (c.Name == (selector.Contains(":") ? GetEvent(selector).Key.Replace("#", "").Replace(".", "") : selector))
                {
                    ret.Add(c);
                }
                else if (c is IStylableControl)
                {
                    var ccc = c as IStylableControl;
                    if ("." + ccc.Class == selector)
                    {
                        ret.Add(c);
                    }
                    if (c.GetType().BaseType.Name == selector)
                    {
                        ret.Add(c);
                    }
                }
                
            }

            return ret.ToArray();
        }

        private static KeyValuePair<string, string> GetEvent(string first)
        {
            return new KeyValuePair<string, string>(
                first.Split(':')[0].Trim(),
                first.Split(':')[1].Trim());
        }

        #endregion
    }
}